package luz.javaproxy.proxy;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import luz.javaproxy.plugin.PluginMgr;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.NoConnectionReuseStrategy;
import org.apache.http.impl.nio.DefaultServerIOEventDispatch;
import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
import org.apache.http.nio.params.NIOReactorPNames;
import org.apache.http.nio.protocol.ThrottlingHttpServiceHandler;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.nio.reactor.ListeningIOReactor;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpRequestHandlerRegistry;


public class Proxy {
	private static final Log log = LogFactory.getLog(Proxy.class);
	private ListeningIOReactor proxy;
	private ThrottlingHttpServiceHandler proxyHandler;
	private HttpParams proxyParams;
	private HttpProxy httpProxy;

	public Proxy(String host, int port, PluginMgr mgr){
		proxyParams = new BasicHttpParams();
        proxyParams
	        .setIntParameter(		CoreConnectionPNames.SO_TIMEOUT				, 60000)
	        .setIntParameter(		CoreConnectionPNames.CONNECTION_TIMEOUT		, 60000)
	        .setIntParameter(		CoreConnectionPNames.SOCKET_BUFFER_SIZE		, 20 * 1024)
	        .setIntParameter(       NIOReactorPNames.CONTENT_BUFFER_SIZE        , 20 * 1024)
            .setBooleanParameter(	CoreConnectionPNames.STALE_CONNECTION_CHECK	, true)
            .setBooleanParameter(	CoreConnectionPNames.TCP_NODELAY			, true);

        BasicHttpProcessor proxyProc = new BasicHttpProcessor();

        proxyHandler = new  ThrottlingHttpServiceHandler(
        		proxyProc, 
	        	new DefaultHttpResponseFactory(), 
	        	new NoConnectionReuseStrategy(), 
	        	Executors.newFixedThreadPool(3),
	        	proxyParams); 

//        proxyHandler = new BufferingHttpServiceHandler(
//                proxyProc,
//                new DefaultHttpResponseFactory(),
//                new DefaultConnectionReuseStrategy(),
//                proxyParams);

        // Set up request handlers
        HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
        httpProxy = new HttpProxy(mgr);
        reqistry.register("*", httpProxy);
        proxyHandler.setHandlerResolver(reqistry);
        proxyHandler.setEventListener(new ProxyEventLogger());
        
		try {
			proxy = new DefaultListeningIOReactor(1, proxyParams);
			proxy.listen(new InetSocketAddress(host, port));
		} catch (IOReactorException e) {
			log.error("IOReactorException ", e);
		}
    	log.info("Proxy loaded");
	}
	
    public void run() throws IOException {
    	proxy.execute(new DefaultServerIOEventDispatch(proxyHandler, proxyParams));
    }
    
    
    public void shutdown() {
    	httpProxy.shutdown();
		try {
			proxy.shutdown();
		} catch (IOException e) {
			log.warn("Shutdown error", e);
		}
    	
    }

}
